package com.csmht.tododemo.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.read.listener.ReadListener;
import com.csmht.tododemo.constant.MessageConstant;
import com.csmht.tododemo.constant.RedisKeyConstant;
import com.csmht.tododemo.exiception.BaseException;
import com.csmht.tododemo.exiception.ServiceException;
import com.csmht.tododemo.mapper.ClassMapper;
import com.csmht.tododemo.mapper.TodoClassMapper;
import com.csmht.tododemo.mapper.TodoMapper;
import com.csmht.tododemo.pojo.dto.CommentPageDTO;
import com.csmht.tododemo.pojo.dto.PageDTO;
import com.csmht.tododemo.pojo.dto.ToDoDTO;
import com.csmht.tododemo.pojo.entity.TodoClass;
import com.csmht.tododemo.pojo.entity.Todo;
import com.csmht.tododemo.pojo.entity.TodoExcel;
import com.csmht.tododemo.pojo.vo.ToDoVO;
import com.csmht.tododemo.service.TodoService;
import com.csmht.tododemo.until.BaseUnit;
import com.csmht.tododemo.until.VisitorUrlUntil;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.csmht.tododemo.constant.MessageConstant.ID_IS_NULL;

/**
 * TodoServiceImpl - 待办事项业务逻辑实现类
 * 实现TodoService接口定义的所有业务方法
 * 主要功能包括：
 * 1. 待办事项的增删改查操作
 * 2. 待办事项与分类的关联管理
 * 3. Excel数据导入功能
 * 4. 待办事项状态管理
 */
@Service
public class TodoServiceImpl implements TodoService {

    @Resource
    private TodoMapper todoMapper;

    @Resource
    private TodoClassMapper todoClassMapper;

    @Resource
    private ClassMapper classMapper;



    /**
     * 添加新的待办事项
     * @param toDoDTO 待办事项数据传输对象，包含标题、内容、截止日期等信息
     * @Transactional 事务注解，确保待办事项和分类关联数据的一致性
     */
    @Transactional
    public void add(ToDoDTO toDoDTO) {

        // 创建待办事项实体对象
        Todo todo = Todo.builder().build();

        // 复制DTO属性到实体对象
        BeanUtils.copyProperties(toDoDTO,todo);
        List<Long> classes = toDoDTO.getClasss();

        // 设置默认属性
        todo.setCreateTime(LocalDateTime.now()); // 创建时间设为当前时间
        todo.setStatus(0); // 初始状态设为0(未完成)
        todo.setCreateUser(BaseUnit.getCurrentId()); // 创建人ID从当前上下文获取

        // 保存待办事项到数据库
        todoMapper.insert(todo);

        // 如果有关联分类，保存待办事项与分类的关联关系
        if(classes != null && !classes.isEmpty()){
            todoClassMapper.insert(todo.getId(),classes);
        }


    }



    /**
     * 删除待办事项
     * @param toDoDTO 包含待办事项ID的数据传输对象
     * @Transactional 事务注解，确保待办事项和关联数据同时删除
     */
    @Override
    @Transactional
    public void del(ToDoDTO toDoDTO) {

        Long id = toDoDTO.getId();

        if(id == null){
            throw new BaseException(ID_IS_NULL);
        }

        todoMapper.del(id);
        todoClassMapper.del(id);

    }


    /**
     * 更新待办事项信息
     * @param dto 包含更新信息的数据传输对象
     * @Transactional 事务注解，确保更新操作的原子性
     */
    @Override
    @Transactional
    public void update(ToDoDTO dto) {

        Todo todo = Todo.builder().build();

        BeanUtils.copyProperties(dto,todo);

        todoMapper.update(todo);

        if (dto.getClasss() != null && !dto.getClasss().isEmpty()) {
            todoClassMapper.del(todo.getId());
            todoClassMapper.insert(todo.getId(),dto.getClasss());
        }

    }


    /**
     * 分页查询当前用户的待办事项列表
     * @param pageDTO 分页查询参数，包含页码和每页条数
     * @return 待办事项视图对象列表，包含待办事项基本信息和关联分类
     */
    public List<ToDoVO> list(PageDTO pageDTO) {

        Long userId = BaseUnit.getCurrentId();

        pageDTO.setPage((pageDTO.getPage()  - 1) * pageDTO.getRows());

        List<Todo> page = todoMapper.page(userId, pageDTO);

        List<ToDoVO> ans = new ArrayList<>();

        page.forEach(todo -> {
            ToDoVO toDoVO = ToDoVO.builder()
                    .id(todo.getId())
                    .title(todo.getTitle())
                    .message(todo.getMessage())
                    .ddl(todo.getDdl())
                    .status(todo.getStatus())
                    .classs(classMapper.selectByToDoId(todo.getId()))
                    .build();
            ans.add(toDoVO);
        });


        return ans;
    }


    /**
     * 根据ID查询待办事项详情
     * @param id 待办事项ID
     * @return 待办事项视图对象，包含完整信息和关联分类
     */
    @Override
    public ToDoVO getById(Long id) {

        Todo todo = todoMapper.selectById(id);
         return getTodoVoByTodo(todo);
    }

    /**
     * 将Todo实体对象转换为ToDoVO视图对象
     * @param todo 待办事项实体对象
     * @return 转换后的视图对象，包含关联分类信息
     */
    private ToDoVO getTodoVoByTodo(Todo todo){
        List<Long> a = todoClassMapper.selectByTodoId(todo.getId());


        List<TodoClass> todoClasses = classMapper.selectByIds(a);

        return ToDoVO.builder()
                .classs(todoClasses)
                .ddl(todo.getDdl())
                .title(todo.getTitle())
                .id(todo.getId())
                .message(todo.getMessage())
                .status(todo.getStatus())
                .build();
    }


    /**
     * 更新待办事项状态
     * @param toDoDTO 包含待办事项ID和新状态的数据传输对象
     */
    @Override
    public void status(ToDoDTO toDoDTO) {

        Todo todo = Todo.builder()
                .id(toDoDTO.getId())
                .status(toDoDTO.getStatus())
                .build();

        todoMapper.update(todo);

    }


    /**
     * 从Excel文件导入待办事项数据
     * 使用EasyExcel读取Excel内容并批量保存
     * @param file 上传的Excel文件
     * @throws IOException 如果文件读取失败抛出异常
     */
    @Override
    public void data(MultipartFile file) {
        try {

            List<Long> longs = todoMapper.selectTodoIdByUserId(BaseUnit.getCurrentId());


            EasyExcel.read(
                    file.getInputStream(),
                    TodoExcel.class,
                    // 创建Excel解析监听器
                    new AnalysisEventListener<TodoExcel>() {

                        final List<Todo> list = new ArrayList<>();
                        final List<TodoExcel> todoExcels = new ArrayList<>();


                        /**
                        * 每解析一行Excel数据触发此方法
                        * @param todoExcel Excel行数据映射的对象
                        * @param analysisContext 解析上下文
                        */
                        @Override
                        public void invoke(TodoExcel todoExcel, AnalysisContext analysisContext) {
                            Todo todo = Todo.builder().build();

                            BeanUtils.copyProperties(todoExcel,todo);

                            if(longs == null || longs.stream().noneMatch(id -> Objects.equals(id, todo.getId()))){
                                list.add(todo);
                                todoExcels.add(todoExcel);
                            }

                        }


                        /**
                        * 所有Excel数据解析完成后触发此方法
                        * 用于批量保存解析后的数据
                        * @param analysisContext 解析上下文
                        */
                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {

                            if(list.isEmpty()){
                                return;
                            }

                            todoMapper.insertList(list);

                            for(int i =0; i<list.size(); i++){

                                Todo todo = list.get(i);
                                String[] split = todoExcels.get(i).getClassName().split(",");
                                List<String> list1 = Arrays.stream(split).toList();
                                todoClassMapper.insertByNames(todo,list1);
                            }


                        }
                    }
            ).sheet().doRead();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }


    @Override
    public byte[] export() {

        Long userId = BaseUnit.getCurrentId();

        List<Todo> todoList = todoMapper.select(userId);
        List<TodoExcel> todoExcels = new ArrayList<>();

        todoList.forEach(todo -> {
            List<TodoClass> todoClasses = classMapper.selectByToDoId(todo.getId());
            TodoExcel todoExcel = new TodoExcel();
            BeanUtils.copyProperties(todo,todoExcel);
            StringBuilder className = new StringBuilder();
            todoClasses.forEach(item ->{
                className.append(item.getName()).append(",");
            });
            todoExcel.setClassName(String.valueOf(className));
            todoExcels.add(todoExcel);
        });

        try{
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            // 写入数据到内存流
            EasyExcel.write(outputStream, TodoExcel.class)
                    .sheet("TODO")
                    .doWrite(todoExcels);

            // 3. 获取字节数组形式的文件数据
            return outputStream.toByteArray();
        } catch (Exception e) {
            throw new ServiceException(MessageConstant.SER_DIE);
        }

    }


    @Override
    public String put(Long todoId) {

        Todo todo = todoMapper.selectById(todoId);

        if(!Objects.equals(todo.getCreateUser(), BaseUnit.getCurrentId())){
            throw new BaseException(MessageConstant.TODO_NULL);
        }

        ToDoVO toDoVO = ToDoVO.builder().build();

        BeanUtils.copyProperties(todo,toDoVO);

        toDoVO.setClasss(classMapper.selectByToDoId(todoId));

        StringBuilder url = new StringBuilder();

        try {
            url.append(VisitorUrlUntil.encrypt(String.valueOf(todoId)));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }



        todoMapper.update(Todo.builder().id(todoId).visitor(1).build());

        return url.toString();
    }


    @Override
    public void delVisitor(Long todoId) {
        Todo todo = Todo.builder()
                .id(todoId)
                .visitor(0)
                .build();

        todoMapper.update(todo);
    }

    @Override
    public List<ToDoVO> getAll(CommentPageDTO commentPageDTO) {


        List<Todo> todos = todoMapper.getAllVisitor();


        List<ToDoVO> ans = new ArrayList<>();

        todos.forEach(todo -> {
            List<TodoClass> todoClasses = classMapper.selectByToDoId(todo.getId());
            ToDoVO toDoVO = ToDoVO.builder().build();

            BeanUtils.copyProperties(todo,toDoVO);
            toDoVO.setClasss(todoClasses);
            ans.add(toDoVO);
        });

        return ans;
    }

}